using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using Cysharp.Threading.Tasks;
using Spine;
using Spine.Unity;
using UnityEngine;
using System.Threading;
using UnityEditor;

[RequireComponent(typeof(DynamicObject))]
public class SpineTouchManager : MonoBehaviour
{
    public SpineTouchConfigSO configSo;
    
    private SpineTouchAnimation defaultAnimation;
    
    private List<SpineAnimLayer> animLayerSortIndex;
    
    private List<SpineTouchConfig> touchConfigs = new List<SpineTouchConfig>();

    private SkeletonGraphic skeletonGraphic;

    private DynamicObject dynamicObject;
    
    private SkeletonUtility skeletonUtility;

    private bool enableTouch = true;

    private Dictionary<SpineTouchConfig, SpineTouchUnit> unitDict = new();

    private CancellationTokenSource _tokenSource;

    //正在播放的轨道，播放动画选项没有勾线stay且不是0的会被添加到这里，当播放其他动画时就会被清空
    private List<int> onPlayTrackIndex = new();
    
    private Dictionary<string, int> animLayerDict = new();

    private void Awake()
    {
        //初始化组件
        dynamicObject = GetComponent<DynamicObject>();
        skeletonGraphic = GetComponent<SkeletonGraphic>();
        skeletonUtility = GetComponent<SkeletonUtility>();
        //初始化数据
        InitData();
    }

    public void Start()
    {
        //生成点击控件
        CreateTouchPoint();
    }

    private void InitData()
    {
        dynamicObject.definitions = configSo.definitions;
        defaultAnimation = configSo.defaultAnimation;
        animLayerSortIndex = configSo.animLayerSortIndex;
        touchConfigs.Clear();
        foreach (var group in configSo.configGroups)
        {
            touchConfigs.AddRange(group.configs);
        }
        
        InitAnimLayer();
        dynamicObject.Initialize();
    }

    private void InitAnimLayer()
    {
        InitAnimLayerDict(skeletonGraphic.skeletonDataAsset,animLayerSortIndex,ref animLayerDict);
        
        skeletonGraphic.startingLoop = true;
        skeletonGraphic.Initialize(true);
        skeletonGraphic.AnimationState.SetAnimation((int)defaultAnimation.layer, defaultAnimation.animation, true);
    }

    public static void InitAnimLayerDict(SkeletonDataAsset skeletonDataAsset, List<SpineAnimLayer> layerIndex,ref Dictionary<string,int> layerDict)
    {
        var animData = skeletonDataAsset.GetSkeletonData(true);
        var index = 1;
        layerDict.Clear();
        foreach (var animDataAnimation in animData.Animations)
        {
            layerDict.Add(animDataAnimation.Name, index * 10);
            index++;
        }
        foreach (var spineAnimLayer in layerIndex)
        {
            if (layerDict.ContainsKey(spineAnimLayer.animName))
            {
                layerDict[spineAnimLayer.animName] = spineAnimLayer.layer;
            }
        }
    }
    
    private void CreateTouchPoint()
    {
        //生成根节点
        GameObject touchRoot;
        if (transform.Find("TouchRoot") == null)
        {
            touchRoot = new GameObject("TouchRoot");
            touchRoot.transform.SetParent(transform, false);
            touchRoot.transform.localPosition = Vector3.zero;
        }
        else
        {
            touchRoot = transform.Find("TouchRoot").gameObject;
        }

        Dictionary<string,SkeletonUtilityBone> boneDict = new();
        foreach (var utilityBone in skeletonUtility.boneRoot.GetComponentsInChildren<SkeletonUtilityBone>())
        {
            boneDict.Add(utilityBone.boneName, utilityBone);
        }
        
        foreach (var touchConfig in touchConfigs)
        {
            if (!boneDict.ContainsKey(touchConfig.skeleton))
            {
                continue;
            }
            
            //初始化数据
            InitParameter(touchConfig, dynamicObject);
            
            //生成跟随的交互控件
            var touchObj = new GameObject(touchConfig.skeleton);
            touchObj.transform.SetParent(touchRoot.transform, false);
            var touchUnit = touchObj.AddComponent<SpineTouchUnit>();
            touchUnit.Init(touchConfig, boneDict[touchConfig.skeleton], dynamicObject, () => { OnClick(touchUnit, touchConfig); });
            unitDict.Add(touchConfig, touchUnit);
        }

        ShowUnLockPoint();
    }
    
    private void InitParameter(SpineTouchConfig touchConfig,DynamicObject dyObj)
    {
        foreach (var touchEvent in touchConfig.events)
        {
            //状态参数
            foreach (var parameterState in touchEvent.paramterStates)
            {
                parameterState.Init(dyObj);
            }

            //更新参数
            foreach (var changeParameter in touchEvent.changeParamter)
            {
                changeParameter.Init(dyObj);
            }
        }
    }

    private void ShowUnLockPoint()
    {
        foreach (var (config, unit) in unitDict)
        {
            unit.gameObject.SetActive(config.IsUnLock(skeletonGraphic, dynamicObject));
        }
    }

    private void OnClick(SpineTouchUnit touchUnit, SpineTouchConfig touchConfig)
    {
        if (!enableTouch)
        {
            return;
        }

        List<SpineTouchParamterState> changeParamters = new();

        List<SpineTouchEvent> invokeEvents = new();

        foreach (var touchEvent in touchConfig.events)
        {
            //检查是否满足前提条件
            if (!touchEvent.IsUnLock(skeletonGraphic, dynamicObject))
            {
                continue;
            }

            invokeEvents.Add(touchEvent);
        }

        if (touchConfig.invokeNum == SpineTouchEventInvokeNum.Single) //只能有一个事件触发
        {
            var randomEvent = invokeEvents[UnityEngine.Random.Range(0, invokeEvents.Count)];
            invokeEvents.Clear();
            invokeEvents.Add(randomEvent);
        }

        int count = 0;
        float delayToUpdatePoint = 0f;
        bool forceComplete = false;

        //清空旧轨道
        foreach (var trackIndex in onPlayTrackIndex)
        {
            skeletonGraphic.AnimationState.ClearTrack(trackIndex);
        }

        foreach (var touchEvent in invokeEvents)
        {
            //播放动画
            foreach (var playAnimation in touchEvent.playAnimations)
            {
                if (playAnimation.forceComplete)
                {
                    forceComplete = true;
                }

                int layer = 0;
                if (playAnimation.layer == SpineTouchAnimationIndex.Base)
                {
                    skeletonGraphic.AnimationState.SetEmptyAnimations(0);
                    layer = (int)playAnimation.layer;
                }
                else
                {
                    if (int.TryParse(playAnimation.animation.Split('_')[1], out var layerIndex))
                    {
                        layer = layerIndex * 10 + count;
                        count++;
                    }

                    if (!animLayerDict.TryGetValue(playAnimation.animation, out layer))
                    {
                        Debug.Log("找不到层级：" + playAnimation.animation);
                    }
                }

                //Debug.Log("播放的层级：" + layer);

                var oldTrack = skeletonGraphic.AnimationState.GetCurrent(layer);
                TrackEntry track = null;

                float totalDuration = 0f;
                if (string.IsNullOrEmpty(playAnimation.animation))
                {
                    track = skeletonGraphic.AnimationState.SetEmptyAnimation(layer, 0);
                }
                else
                {
                    if (oldTrack != null && oldTrack.Animation.Name == "<empty>")
                    {
                        skeletonGraphic.AnimationState.ClearTrack(layer);
                    }


                    // var emptyTrack = skeletonGraphic.AnimationState.SetEmptyAnimation(layer, -2f);
                    // Debug.Log($"空动画名称：{emptyTrack.Animation.Name}");
                    // track = skeletonGraphic.AnimationState.AddAnimation(layer, playAnimation.animation, false, -1f);
                    // Debug.Log("添加：" + playAnimation.animation);

                    track = skeletonGraphic.AnimationState.SetAnimation(layer, playAnimation.animation, false);

                    if (!playAnimation.stay && layer != 0)
                    {
                        onPlayTrackIndex.Add(layer);
                    }
                }

                totalDuration += track.Animation.Duration;

                track.Complete += t =>
                {
                    if (!string.IsNullOrEmpty(playAnimation.endAnimation))
                    {
                        var endTrack = skeletonGraphic.AnimationState.AddAnimation(layer, playAnimation.endAnimation, true, 0f);
                    }
                    else
                    {
                        if (!playAnimation.stay)
                        {
                            skeletonGraphic.AnimationState.SetEmptyAnimation(layer, 2f);
                        }
                    }
                };

                if (totalDuration >= delayToUpdatePoint)
                {
                    delayToUpdatePoint = totalDuration;
                }
            }

            //添加要设置的参数
            if (touchEvent.changeParamter != null && touchEvent.changeParamter.Count > 0)
            {
                changeParamters.AddRange(touchEvent.changeParamter);
            }
        }

        //设置参数
        foreach (var parameterState in changeParamters)
        {
            dynamicObject.SetValue(parameterState.paramterName, parameterState.FieldData);
        }

        //更新触碰点
        DisableTouch(forceComplete ? delayToUpdatePoint + 0.1f : delayToUpdatePoint * 0.5f).Forget();
        UniTask.WaitForSeconds(delayToUpdatePoint + 0.1f).OnComplete(ShowUnLockPoint).Forget();
    }

    private async UniTaskVoid DisableTouch(float resetTime)
    {
        enableTouch = false;
        await UniTask.WaitForSeconds(resetTime);
        enableTouch = true;
    }

    [ContextMenu("复制数据到SO")]
    public void CopyData()
    {
        configSo.defaultAnimation = defaultAnimation;
        configSo.animLayerSortIndex = animLayerSortIndex;

        string GetGroupName(string skName)
        {
            if (skName.Contains("point1"))
            {
                return "wait1";
            }

            if (skName.Contains("point2"))
            {
                return "wait2";
            }

            if (skName.Contains("point3"))
            {
                return "wait3";
            }
            return "Trans";
        }
        
        SpineTouchConfigGroup getGroup(string name)
        {
            SpineTouchConfigGroup group = configSo.configGroups.Find(g => g.groupName == name);
            if (group == null)
            {
                group  = new SpineTouchConfigGroup()
                {
                    groupName = name,
                };
                configSo.configGroups.Add(group);
            }

            return group;
        }
        
        foreach (var touchConfig in touchConfigs)
        {
            var name = touchConfig.skeleton;
            var group = getGroup(GetGroupName(name));
            group.configs.Add(touchConfig);
        }
        
        EditorUtility.SetDirty(configSo);
        AssetDatabase.SaveAssetIfDirty(configSo);
    }
}